--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
scripts/ci/docker-hardened-smoke.sh e41daa5b65e07a5baa1aaad32d97f90482f1cd1c (e41daa5b) Text, 3.75 KB
T8b949e#!/usr/bin/env bash
T8b949e# Build the standard image and verify hardened docker compose stacks and docker run.
Tffa657set -euo pipefail
Te6edf3ROOTTff7b72=Ta5d6ff"Tff7b72$(Tffa657cd Ta5d6ff"Tff7b72$(dirname Ta5d6ff"Te6edf3$0Ta5d6ff"Tff7b72)Ta5d6ff/../..Ta5d6ff" Tff7b72&& Tffa657pwdTff7b72)Ta5d6ff"
Tffa657cd Ta5d6ff"Te6edf3$ROOTTa5d6ff"
Te6edf3IMAGETff7b72=Ta5d6ff"Tffd700${Te6edf3MESHCHAT_DOCKER_SMOKE_IMAGETff7b72:-Te6edf3reticulumTb4b4b4-meshchatxTb4b4b4:Te6edf3localTffd700}Ta5d6ff"
Te6edf3RUN_CONTAINERTff7b72=Ta5d6ff"Tffd700${Te6edf3MESHCHAT_DOCKER_RUN_SMOKE_CONTAINERTff7b72:-Te6edf3meshchatxTb4b4b4-hardened-run-testTffd700}Ta5d6ff"
Te6edf3RUN_PORTTff7b72=Ta5d6ff"Tffd700${Te6edf3MESHCHAT_DOCKER_RUN_SMOKE_PORTTff7b72:-Te6edf318081Tffd700}Ta5d6ff"
Te6edf3TIMEOUT_SECTff7b72=Ta5d6ff"Tffd700${Te6edf3MESHCHAT_DOCKER_SMOKE_TIMEOUTTff7b72:-Te6edf3180Tffd700}Ta5d6ff"
Te6edf3CONFIG_DIRTff7b72=Ta5d6ff"Tffd700${Te6edf3MESHCHAT_DOCKER_SMOKE_CONFIGTff7b72:-Tff7b72$(mktemp -dTff7b72)Tffd700}Ta5d6ff"
cleanupTff7b72(Tff7b72) Tff7b72{
docker compose -f docker-compose.yml down >/dev/null T79c0ff2>Tb4b4b4&T79c0ff1 Tff7b72|| Tffa657true
docker compose -f docker-compose.dev.yml down >/dev/null T79c0ff2>Tb4b4b4&T79c0ff1 Tff7b72|| Tffa657true
docker compose -f docker-compose.coolify.yml down >/dev/null T79c0ff2>Tb4b4b4&T79c0ff1 Tff7b72|| Tffa657true
docker rm -f Ta5d6ff"Te6edf3$RUN_CONTAINERTa5d6ff" >/dev/null T79c0ff2>Tb4b4b4&T79c0ff1 Tff7b72|| Tffa657true
Tff7b72if Tff7b72[ Ta5d6ff"Tffd700${Te6edf3MESHCHAT_DOCKER_SMOKE_KEEP_CONFIGTff7b72:-Te6edf30Tffd700}Ta5d6ff" !Tff7b72= Ta5d6ff"1" Tff7b72] Tff7b72&& Tff7b72[ -n Ta5d6ff"Tffd700${Te6edf3TMP_CONFIG_CREATEDTff7b72:-Tffd700}Ta5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
rm -rf Ta5d6ff"Te6edf3$CONFIG_DIRTa5d6ff"
Tff7b72fi
Tff7b72}
Tffa657trap cleanup EXIT
Tff7b72if Tff7b72[ -z Ta5d6ff"Tffd700${Te6edf3MESHCHAT_DOCKER_SMOKE_CONFIGTff7b72:-Tffd700}Ta5d6ff" Tff7b72]Tb4b4b4; Tff7b72then
Te6edf3TMP_CONFIG_CREATEDTff7b72=T79c0ff1
Tff7b72fi
chmod T79c0ff777 Ta5d6ff"Te6edf3$CONFIG_DIRTa5d6ff"
wait_httpsTff7b72(Tff7b72) Tff7b72{
Tffa657local Te6edf3portTff7b72=Ta5d6ff"Te6edf3$1Ta5d6ff"
Tffa657local Te6edf3deadlineTff7b72=Tff7b72$((Te6edf3SECONDS Tff7b72+ Te6edf3TIMEOUT_SECTff7b72))
Tff7b72while Tff7b72[ Ta5d6ff"Te6edf3$SECONDSTa5d6ff" -lt Ta5d6ff"Te6edf3$deadlineTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72do
Tff7b72if Te6edf3outTff7b72=Tff7b72$(curl -fsSk Ta5d6ff"Ta5d6ffhttps://127.0.0.1:Tffd700${Te6edf3portTffd700}Ta5d6ff/api/v1/statusTa5d6ff" T79c0ff2>/dev/nullTff7b72) Tff7b72&&
Tffa657printf Ta5d6ff'%s' Ta5d6ff"Te6edf3$outTa5d6ff" Tb4b4b4| python3 -c Ta5d6ff'import json,sys; d=json.load(sys.stdin); sys.exit(0 if d.get("status")=="ok" else 1)'Tb4b4b4; Tff7b72then
Tffa657echo Ta5d6ff"Te6edf3$outTa5d6ff"
Tff7b72return T79c0ff0
Tff7b72fi
sleep T79c0ff3
Tff7b72done
Tff7b72return T79c0ff1
Tff7b72}
wait_container_healthyTff7b72(Tff7b72) Tff7b72{
Tffa657local Te6edf3nameTff7b72=Ta5d6ff"Te6edf3$1Ta5d6ff"
Tffa657local Te6edf3deadlineTff7b72=Tff7b72$((Te6edf3SECONDS Tff7b72+ Te6edf3TIMEOUT_SECTff7b72))
Tffa657local Te6edf3stateTff7b72=Ta5d6ff""
Tff7b72while Tff7b72[ Ta5d6ff"Te6edf3$SECONDSTa5d6ff" -lt Ta5d6ff"Te6edf3$deadlineTa5d6ff" Tff7b72]Tb4b4b4; Tff7b72do
Te6edf3stateTff7b72=Tff7b72$(docker inspect --format Ta5d6ff'{{if .State.Health}}{{.State.Health.Status}}{{else}}none{{end}}' Ta5d6ff"Te6edf3$nameTa5d6ff" T79c0ff2>/dev/null Tff7b72|| Tffa657echo missingTff7b72)
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$stateTa5d6ff" Tff7b72= Ta5d6ff"healthy" Tff7b72]Tb4b4b4; Tff7b72then
Tff7b72return T79c0ff0
Tff7b72fi
Tff7b72if Tff7b72[ Ta5d6ff"Te6edf3$stateTa5d6ff" Tff7b72= Ta5d6ff"unhealthy" Tff7b72]Tb4b4b4; Tff7b72then
docker logs Ta5d6ff"Te6edf3$nameTa5d6ff" >Tb4b4b4&T79c0ff2 Tff7b72|| Tffa657true
Tff7b72return T79c0ff1
Tff7b72fi
sleep T79c0ff3
Tff7b72done
Tffa657echo Ta5d6ff"Ta5d6ffTimed out waiting for container health (last state: Tffd700${Te6edf3stateTffd700}Ta5d6ff)Ta5d6ff" >Tb4b4b4&T79c0ff2
docker logs Ta5d6ff"Te6edf3$nameTa5d6ff" >Tb4b4b4&T79c0ff2 Tff7b72|| Tffa657true
Tff7b72return T79c0ff1
Tff7b72}
Tffa657echo Ta5d6ff"Ta5d6ffBuilding Docker image Tffd700${Te6edf3IMAGETffd700}Ta5d6ff...Ta5d6ff"
docker build -f Dockerfile -t Ta5d6ff"Te6edf3$IMAGETa5d6ff" .
Tffa657echo Ta5d6ff"=== docker-compose.yml (hardened) ==="
Te6edf3MESHCHAT_IMAGETff7b72=Ta5d6ff"Te6edf3$IMAGETa5d6ff" docker compose -f docker-compose.yml up -d --pull never
wait_container_healthy reticulum-meshchatx
wait_https T79c0ff8000 >/dev/null
docker compose -f docker-compose.yml down
Tffa657echo Ta5d6ff"=== docker-compose.dev.yml (hardened) ==="
docker compose -f docker-compose.dev.yml up -d --pull never
wait_container_healthy reticulum-meshchatx
wait_https T79c0ff8000 >/dev/null
docker compose -f docker-compose.dev.yml down
Tffa657echo Ta5d6ff"=== docker-compose.coolify.yml (hardened) ==="
Te6edf3MESHCHAT_IMAGETff7b72=Ta5d6ff"Te6edf3$IMAGETa5d6ff" docker compose -f docker-compose.coolify.yml up -d --pull never
Te6edf3coolify_cidTff7b72=Tff7b72$(docker compose -f docker-compose.coolify.yml ps -q meshchatxTff7b72)
wait_container_healthy Ta5d6ff"Te6edf3$coolify_cidTa5d6ff"
docker Tffa657exec Ta5d6ff"Te6edf3$coolify_cidTa5d6ff" python -c Ta5d6ff"import urllib.request; print(urllib.request.urlopen('http://127.0.0.1:8000/api/v1/status').read().decode())" >/dev/null
docker compose -f docker-compose.coolify.yml down
Tffa657echo Ta5d6ff"=== docker run (hardened) ==="
docker run -d --name Ta5d6ff"Te6edf3$RUN_CONTAINERTa5d6ff" Tffea00\
--restart unless-stopped Tffea00\
--init Tffea00\
--user T79c0ff1000:1000 Tffea00\
--security-opt no-new-privileges:true Tffea00\
--cap-drop ALL Tffea00\
--read-only Tffea00\
--tmpfs /tmp:noexec,nosuid,sizeTff7b72=256m Tffea00\
--tmpfs /home/meshchat:nosuid,sizeTff7b72=64m Tffea00\
--cpusTff7b72=T79c0ff2.0 Tffea00\
--memoryTff7b72=1g Tffea00\
--memory-reservationTff7b72=256m Tffea00\
--pids-limitTff7b72=T79c0ff512 Tffea00\
-p Ta5d6ff"Ta5d6ff127.0.0.1:Tffd700${Te6edf3RUN_PORTTffd700}Ta5d6ff:8000Ta5d6ff" Tffea00\
-v Ta5d6ff"Tffd700${Te6edf3CONFIG_DIRTffd700}Ta5d6ff:/configTa5d6ff" Tffea00\
Ta5d6ff"Te6edf3$IMAGETa5d6ff" >/dev/null
Te6edf3status_jsonTff7b72=Tff7b72$(wait_https Ta5d6ff"Te6edf3$RUN_PORTTa5d6ff"Tff7b72)
Tffa657echo Ta5d6ff"Ta5d6ffDocker hardened smoke passed: Tffd700${Te6edf3status_jsonTffd700}Ta5d6ff"
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────